home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / lang_c / cug191 / clink80.c < prev    next >
C/C++ Source or Header  |  1986-07-10  |  17KB  |  494 lines

  1. /* CLINK/80 v. 6-9-85 compile with -k switch         */
  2. /* Linkage of C/80 source code subroutines           */
  3. /* Phillip L. Emerson   Cleveland State University   */
  4. /* first version, 4-24-84                            */
  5. /* modified 9-17-84 for some filenames in output     */
  6. /* modified 2-20-85 for single pass if keyfile exists*/
  7. /* modified 6-7-85: took out #define DONOTHING, put in
  8.    #define LF,SP; simplified a few routines; hashlist
  9.    structures now used for both data bases -- library
  10.    function intercalls (table1) and program function
  11.    calls netted up (table2). Also, routine netup() was
  12.    modified to erase its tracks to prevent endless
  13.    cycling (stack overflow) with cycling function calls */
  14.  
  15.       /* some modifiable parameters */
  16. #define SAME 0
  17. #define LESS -1
  18. #define MORE 1
  19. #define ONE 1
  20. #define VOID -1
  21. #define NULL 0
  22. #define UNDRSC '\137'   /*assumes ASCII*/
  23. #define BELL '\007'
  24. #define APOSTR '\047'
  25. #define QUOTE '\042'
  26. #define BACKSL '\134'
  27. #define LF '\n'
  28. #define SP '\40'
  29. #define BUFSIZ 5000      /*must hold any lib. func.*/
  30. #define NAMSIZ 20        /*max length of func. names*/
  31. #define HASHSIZ 512      /*size of hash table       */
  32. #define LINSIZ 140       /*source-code max line  ln */
  33. #define FNAMSZ 20        /*max len. of file names   */
  34. #define OFFSET 20        /*buff offset for backup    */
  35. #define MARGA 10         /*error margin for buff ovfl */
  36. #define MARGB 15         /*error margin for buff ovfl */
  37. #define alloc sbrk       /*a C/80 optional primitive alloc */
  38. char progfil[FNAMSZ],libfil[FNAMSZ],keyfil[FNAMSZ],outfil[FNAMSZ];
  39. char *fubuff, *linebuf ;
  40. int prchan,lichan,keychan,ouchan,quotes,apostrs,combal;
  41.  
  42. /* some functs. before main */
  43.  
  44. /* next f name into r, from string starting
  45.    at p -- return 0 if end reached */
  46. char *funam(p,r) char *p,*r; {char *t,*q,*s,*u; int n;
  47.   u = r ;
  48. loop: s = p; r = u ;
  49.    while ((*p) && (*p != '(' )) p++ ;
  50.    if (*p == NULL) return(NULL) ;
  51.    t = p-- ;
  52.    while ((*p == ' ' ) && (p > s)) p-- ;
  53.    q = p ;
  54.    if( !lglname(*q)) { p = ++t ; goto loop ; }
  55.    while ( lglname(*q) && (q >= s)) q-- ;
  56.    q++ ;
  57.    for(n=1; (n < (NAMSIZ-1)) && (q <= p); *r++ = *q++,n++) ;
  58.    *r = NULL;
  59.    if ((q < s) || (n >= (NAMSIZ-1)) || (n <= 0))
  60.       {putstr("error in processing name\n") ;
  61.        putstr(u); putchar(LF); exit(); }
  62.    if (systn(u)) { p = ++t; goto loop; }
  63.    return(++t) ; }
  64.  
  65. /* list of commen system function names to ignore */
  66. #define SNAMES 19  /* nr of names*/
  67. char *sysnam(n) int n;
  68. {static char *name[] = {
  69. "if","for","while","fclose","fopen","getc",
  70. "putc","write","read","getchar","putchar",
  71. "alloc","return","main","seek","ftell",
  72. "ftellr","exec","switch" } ; return(name[n]) ; }
  73.  
  74. /* Mod2 counting of apostrophes and quotes */
  75. char quotap(n) char n; {static char last;
  76.   if(( n == QUOTE) && (last != BACKSL ) && !apostrs)
  77.      quotes = ((quotes+1) % 2) ;
  78.   if(( n == APOSTR) && (last != BACKSL) && !quotes)
  79.      apostrs=((apostrs+1) % 2) ;
  80.   last = n ;
  81.   return(n) ; }
  82.  
  83. /* allocate space for s, store s, and return ptr to it */
  84. char *strsave(s) char *s; {char *p ;
  85.    if (((p=alloc(strlen(s)+1)) == VOID) || (p == NULL))
  86.           return(NULL) ;
  87.    strcpy(p,s); return(p) ; }
  88.  
  89. /* search for string q on p. rtrn ptr to it if so, null if not*/
  90. char *strison(p,q) char *p,*q; {
  91.    for( ; *p ; p++) {if(strisat(p,q)) return(p) ; }
  92.    return(NULL) ; }
  93.  
  94. /* standard getch & ungetch to be used in next routine*/
  95. int getctr ;
  96. char getcbuf[5] ;
  97. char getch()
  98.   { if(getctr) return (getcbuf[--getctr]); return(getc(lichan)) ; }
  99. ungetch(a) char a;
  100.   {getcbuf[getctr++] = a; return; }
  101.  
  102. /* get a char from libchan, ignoring literals & comments */
  103. char gignor()
  104. { char n,m;
  105. loop1: if ((n=getch()) == VOID) return(VOID) ;
  106.    if((n != '/') || quotes || apostrs) return(quotap(n)) ;
  107.    if((m=getch()) != '*') {ungetch(m) ; return(quotap(n)) ; }
  108. loop2: while (((m=getch()) != '*') && (m != VOID))
  109.         {n=getch(); ungetch(n);
  110.          if((m == '/') && (n == '*')) combal++ ; }
  111.    if (m == VOID) return(VOID) ;
  112.    if((m=getch()) != '/') {ungetch(m) ; goto loop2; }
  113.    goto loop1; }
  114.  
  115. oulab() {putl("/* file ",ouchan);putl(outfil,ouchan);putl(" */\n",ouchan);}
  116.  
  117. struct list {
  118. char *hashkey ;
  119. char *defntn ;
  120. struct list *next ; } ;
  121. struct list **table1 ;
  122. struct list **table2 ;
  123.  
  124. /*  BEGINNING OF MAIN PROGRAM */
  125. main(argc,argv) int argc; char *argv[];
  126. {  putstr("CLINK/80 v. 6-9-85\n") ;
  127.   linebuf = alloc(LINSIZ) ;
  128.   table1 = (struct list **) alloc(HASHSIZ*(sizeof(struct list *))) ;
  129.   table2 = (struct list **) alloc(HASHSIZ*(sizeof(struct list *))) ;
  130.   tabinit() ;
  131.   fubuff = alloc(BUFSIZ) ;
  132.   if( (fubuff == NULL) || (fubuff == VOID))
  133.     {putstr("not enough room for buffer\n"); exit(); }
  134.   strcpyn(progfil,argv[1],FNAMSZ-1) ;
  135.   strcpyn(libfil,argv[2],FNAMSZ-1) ;
  136.   strcpyn(keyfil,argv[3],FNAMSZ-1) ;
  137.   strcpyn(outfil,argv[4],FNAMSZ-1) ;
  138.   if (argc >= 2)
  139.       { if ( !strison(progfil,"."))
  140.             strcpy(progfil+strlen(progfil),".B") ;
  141.         if (argc < 5) strcpyc(outfil,progfil,'.') ;
  142.         if (argc < 4) strcpy(keyfil,"LIBKEY.B") ;
  143.         if (argc < 3) strcpy(libfil,"USRLIB.B") ;
  144.         defalt(progfil,keyfil,".B") ;
  145.         defalt(progfil,libfil,".B") ;
  146.         defalt(progfil,outfil,".C") ;
  147.         putchar(LF) ;
  148.         putstr(progfil) ; putstr(" program file\n") ;
  149.         putstr(libfil) ; putstr(" library file\n") ;
  150.         putstr(keyfil) ; putstr(" library key file\n") ;
  151.         putstr(outfil) ; putstr(" output file \n") ;
  152.         putstr("press RETURN (or ENTER) to proceed, Ctrl-C to abort\n") ;
  153.         getchar() ;
  154.         hashup() ;
  155.         prchan = foptst(progfil,"r") ;
  156.         ouchan = foptst(outfil,"w") ;
  157.         oulab() ;
  158.         buildup(1) ;
  159.      }
  160.  else
  161.      {  putstr("\nlibrary file name? ") ;  getstr(libfil) ;
  162.         putstr("\nlibrary keys file name? "); getstr(keyfil) ;
  163.         putstr("wait -- getting library keys\n") ;
  164.         hashup() ;
  165.         putstr("output file name? ") ;  getstr(outfil) ;
  166.         ouchan = foptst(outfil,"w") ; oulab() ;
  167.         for (*progfil='1'; (*progfil) && (*progfil != LF) ; )
  168.           { putstr("input file name? -- ") ;
  169.             putstr("just press RETURN (or ENTER) if no more ") ;
  170.             *progfil = NULL; getstr(progfil) ;
  171.             if ( (*progfil) && (*progfil != LF ) )
  172.               {prchan = foptst(progfil,"r") ;
  173.                putstr("include in output file? (type 0 for no, 1 for yes)\n");
  174.                buildup(getint()) ;
  175.               }
  176.           }
  177.      }
  178.  tidyup() ;
  179.  if (quotes || apostrs || combal)
  180.      {  putchar(LF); putstr("quotes mod2: ") ; printd(quotes) ;
  181.         putchar(LF); putstr("apostrophes mod2: "); printd(apostrs) ;
  182.         putchar(LF) ;
  183.         putstr("occurrences of comment delimiters within comments: ") ;
  184.         printd(combal) ; putchar(LF) ;
  185.      }
  186.  putstr("Linked output file is "); putstr(outfil); putstr("\n\n") ;
  187. }
  188. /*  END OF MAIN PROGRAM */
  189.  
  190. /*  MANY SUBROUTINES FOLLOW -- some of the more general purpose
  191.     ones would ordinarily reside in a library, but this program
  192.     is intended to be fairly self-contained
  193. */
  194.  
  195. /* Manipulation for defaults on file names */
  196. defalt(fpr,fothr,ext) char *fpr,*fothr,*ext;
  197.   {  char *a,temp[FNAMSZ]; int n;
  198.      if( !strison(fothr,":") && (a = strison(fpr,":") ) )
  199.          {  if ( n = a - fpr)
  200.              {  strcpyn(temp,fpr,n+1) ;
  201.                 strcpy(temp+n+1,fothr) ;
  202.                 strcpy(fothr,temp) ;
  203.              }
  204.          }
  205.      if( !strison(fothr,".") ) strcpy(fothr+strlen(fothr),ext) ;
  206.   }
  207.  
  208. /* copy t to s up to but not including 1st instance of char c */
  209. strcpyc(s,t,c) char *s,*t,c;
  210.   { while( (*s++ = *t++) != c)  ; *(--s) = NULL ; }
  211.  
  212. /* tabinit,hash,look,insert are FUNCTIONS FOR HASHING FUNCTION CALLS UNDER
  213.      FUNCTION NAMES
  214. */
  215.  
  216. tabinit()
  217.   {int n; for (n=0; n < HASHSIZ ; n++) table1[n] = table2[n]=NULL ;}
  218.  
  219. hash(s) char *s; {int val;
  220.   for (val=0; *s ;) val += *s++; return(val % HASHSIZ) ; }
  221. struct list *look(s,table) char *s; struct list **table;
  222.   {struct list *p ;
  223.    for (p=table[hash(s)] ; p ; p = p->next )
  224.      { if (strcmp(s,p->hashkey) == SAME) return(p) ; }
  225.    return(NULL) ;
  226.   }
  227. struct list *insert(name,def,table) char *name,*def ;  struct list **table;
  228.   {struct list *n; int val;
  229.    if (n=look(name,table)) return(n) ;
  230.               /* no redefinition of an old one */
  231.    n = (struct list *) alloc(sizeof(struct list)) ;
  232.    if ((n == VOID) || (n == NULL)) putstr("hash error#1\n") ;
  233.    if ((n->hashkey = strsave(name)) == NULL) putstr("hash error#2\n") ;
  234.    val = hash(n->hashkey) ;
  235.    n->next = table[val] ;
  236.    table[val] = n ;
  237.    if ((n->defntn = strsave(def)) == NULL) putstr("hash error#3\n") ;
  238.    return(n) ;
  239.   }
  240.  
  241. /* get byte, starting at staddr, return ptr one past byte position
  242.    in fubuff.  Return VOID if EOF.  Insert NULL at next position
  243.    after byte */
  244. char *getfrst(byte,staddr) char byte,*staddr;
  245.   { char *q;
  246.     for (q=staddr; ( (*q=gignor()) != VOID) && ((*q != byte)
  247.          || quotes || apostrs) && (q < (fubuff+BUFSIZ-MARGA)) ;
  248.                  q++)  ;
  249.     if (*q == VOID) return(VOID) ;
  250.     if (q > (fubuff+BUFSIZ-MARGB)) {putstr("buf ovrfl\n"); exit() ; }
  251.     *++q = NULL ; return(q) ;
  252.        /* q points one past byte position */
  253.   }
  254. /* Return 1 if c is legal in function name, 0 if not */
  255. /* assumes ASCII */
  256. lglname(c) char c ;
  257.   { if( (c >= 'a') && (c <= 'z') ) return(ONE) ;
  258.     if( (c >= 'A') && (c <= 'Z') ) return(ONE) ;
  259.     if( (c >= '0') && (c <= '9') ) return(ONE) ;
  260.     if( c == UNDRSC) return(ONE) ;
  261.     return(NULL) ;
  262.   }
  263. /* compress func. defs. to func. calls */
  264. char *cmprss(brace1) char *brace1;
  265.   { char *p,*q ;
  266.     *fubuff = '{' ;
  267.     q = fubuff; q++;
  268.     for(p=brace1; p=funam(p,q); q += strlen(q), *q++ = '(')  ;
  269.     *q++ = '}' ; *q = NULL ; redcstr(fubuff+1) ;
  270.   }
  271. /* eliminate duplications on compressed definition string */
  272. redcstr(origin) char *origin ;
  273.   { char *p,*q,*r ;
  274.     for (p=origin; *p != '}' ; p++)
  275.       { if (*p == '(' ) *p = NULL ; }
  276.     for (p=origin; *p != '}' ; )
  277.       {q=p;
  278.        while( *q != '}')
  279.          {while( *q != NULL) q++ ;
  280.           while( *q == NULL) q++ ;
  281.           if( *q != '}')
  282.              { if( strcmp(p,q) == SAME)
  283.                  for(r=q; *r != NULL; r++ ) *r = NULL ;
  284.              }
  285.          }
  286.        while( (*p != NULL) && (*p != '}') ) p++ ;
  287.        while( *p == NULL ) p++ ;
  288.       }
  289.     for (p=origin; *p != '}' ; p++)  {if (*p == NULL) *p = '(' ; }
  290.     deruns('(',origin) ;
  291.   }
  292. /* get next lib fn into fubuff, ret name, and pointer to
  293.    opening brace as value
  294. */
  295. char *getfu(name) char *name ;
  296.   {char *brace1,*p,*q,*r; int n,braces ;
  297.    for(q=fubuff+OFFSET,r=q; ((q=getfrst('(',q)) != VOID)
  298.        && (funam(r,name) == NULL) ; r=q)  ;
  299.    if(q == VOID) return(VOID) ;
  300.          /* q will point one past the '(' */
  301.    braces = NULL ;
  302.    if( (q=getfrst('{',q)) == VOID) return(VOID) ;
  303.    brace1 = --q; braces = 1 ;
  304.    while (braces > NULL)
  305.      { *++q = gignor() ;
  306.        if (*q == VOID) return(VOID) ;
  307.        if( (*q == '{') && !quotes && !apostrs) braces += 1;
  308.        if( (*q == '}') && !quotes && !apostrs) braces -= 1;
  309.      }
  310.    *++q = NULL ;
  311.    return(brace1) ;
  312.   }
  313. /* return -1 if string is among those listed as sys. funcs,
  314.    0 of not  */
  315. systn(s) char *s ;
  316.   { int k ;
  317.     for(k=0; k < SNAMES; k++)
  318.       if(strcmp(s,sysnam(k)) == SAME) return(VOID);
  319.     return(NULL) ;
  320.   }
  321. /* new hashup() 2-20-85 -- attempts to read keyfile.  If successful
  322.    ok; if not, hashes up from lib file, and puts out new keyfile */
  323. hashup()
  324.   {char *q,name[NAMSIZ]; struct list *j; int flag;
  325.    getctr=0; quotes=0; apostrs=0;
  326.    if( (flag=keyup()) == 1) return(VOID) ;
  327.    if( flag == VOID) {putstr("insert error on keys\n"); exit(); }
  328.    keychan = foptst(keyfil,"w") ;
  329.    lichan = foptst(libfil,"r") ;
  330.    while( (q=getfu(name)) != VOID)
  331.     {cmprss(q) ;
  332.      if( ( (j=insert(name,fubuff,table1)) == NULL) || (j == VOID) )
  333.        {putstr("insert error from fibfil\n") ; exit() ; }
  334.      putl(name,keychan); putc(LF,keychan) ;
  335.      putl(fubuff,keychan); putc(LF,keychan) ;
  336.     }
  337.    fclose(lichan) ;
  338.    fclose(keychan) ; return(VOID) ;
  339.   }
  340. /* tries to open keyfil for input.  If successful, reads in hash table
  341.    and returns 1.  If not, returns 0, but returns -1 if open to read
  342.    is successful and something goes wrong.  */
  343. keyup()
  344.   {struct list *j ;
  345.    keychan = fopen(keyfil,"r") ;
  346.    if( (keychan == NULL) || (keychan == VOID) )
  347.       {fclose(keychan); return(NULL) ; }
  348.    while( (getl0(linebuf,keychan) != VOID) )
  349.      {getl0(fubuff,keychan) ;
  350.       if( (j=insert(linebuff,fubuff,table1)) == NULL ) return(VOID) ;
  351.       if (j == VOID) return(VOID) ;
  352.      }
  353.    fclose(keychan); return(ONE) ;
  354.   }
  355. /* goes thru prog input file recording names of functions called; arg
  356.    =1 for input into output file, n=0 if not */
  357. buildup(n) int n;
  358.   {while(progli(n) != VOID) ; fclose(prchan) ; }
  359.  
  360. /* processes a line */
  361. progli(n) int n;
  362.   { char *p; static char r[NAMSIZ] ;
  363.     if (getl(linebuf,prchan) == VOID) return(VOID) ;
  364.     if (n) putl(linebuf,ouchan) ;
  365.     for (p=linebuf; p=funam(p,r); netup(r) ) ; return(ONE) ;
  366.   }
  367. /* gets all ramifications of a function call */
  368. /* erasing tracks to prevent endless cycling */
  369. netup(name) char *name ;
  370.   {char *p,*q,r[NAMSIZ] ;  struct list *n;
  371.    insert(name,"1",table2) ;
  372.    if( (n=look(name,table1)) == NULL ) return ;
  373.    p = q = n->defntn ;
  374.    while( p=funam(q,r) )
  375.      {*q = NULL; q = p; if( strcmp(name,r) != SAME ) netup(r) ; }
  376.    return ;
  377.   }
  378. /* goes thru lib file putting out those whose names are recorded */
  379. tidyup()
  380.   {char *p,name[NAMSIZ] ;
  381.    lichan = foptst(libfil,"r") ;
  382.    putl("\n/* routines from library file, ",ouchan) ;
  383.    putl(libfil,ouchan) ; putl("*/\n",ouchan) ;
  384.    putl("/****************************************/\n",ouchan) ;
  385.    getctr = 0; quotes = 0; apostrs = 0; combal = 0;
  386.    while (getfu(name) != VOID)
  387.      { if ( !look(name,table1) )
  388.          {putstr("Warning: lib routine, ");
  389.           putstr(name); putstr(", not indexed.\n") ;
  390.           putchar(BELL) ;
  391.          }
  392.        for ( p=fubuff+OFFSET; *p ; p++)  ;
  393.        *p++ = LF ; *p = NULL ;
  394.        if( look(name,table2) )
  395.          {for (p=fubuff+OFFSET ; *p == LF ; p++ )  ;
  396.           deruns(SP,p); pairdec(SP,LF,p) ; deruns(LF,p) ;
  397.           for ( ; *p ; putc(*p++,ouchan) )  ;
  398.           putl("/**/\n",ouchan) ;
  399.          }
  400.      }
  401.   fclose(ouchan) ;
  402.  }
  403. /* open file if possible, error msg & exit if not */
  404. foptst(file,rw) char *file,*rw ;
  405.  {int chan;
  406.   chan = fopen(file,rw) ;
  407.   if( (chan == NULL) || (chan == VOID) ) ferror(file) ;
  408.   return(chan) ;
  409.  }
  410. /* error msg & exit on errant fopen */
  411. ferror(s) char *s;
  412.  {int i; for (i=1; i < 100; putchar(BELL),i++) ;
  413.   putstr("can't open "); putstr(s); putchar(LF); exit();
  414.  }
  415. /* copy str t to str s */
  416. strcpy(s,t) char *s,*t;
  417.  {while(*s++ = *t++)  ;
  418.  }
  419. /* length of str s, incl. LF if present */
  420. strlen(s) char *s;
  421.  {char *p; p = s; while(*p) p++; return(p-s);
  422.  }
  423. /* get str fm KB, replace LF with NULL at end*/
  424. getstr(a) char *a;
  425.  {int n; n=0;
  426.   if( (*a=getchar()) == VOID) return(VOID) ;
  427.   if( *a == LF ) {*a=NULL; return(NULL);}
  428.   while( (*++a=getchar()) != LF) ++n ;
  429.   *a = NULL; return(n);
  430.  }
  431. /*put str to screen, no auto LF at end*/
  432. putstr(s) char *s;
  433.  {while(*s) putchar(*s++) ;
  434.  }
  435. /* same as putstr, but to chan */
  436. putl(a,chan) char *a; int chan;
  437.  {while(*a) putc(*a++,chan) ;
  438.  }
  439. /* similar to getstr, but from chan, and with LF followed by NULL */
  440. getl(a,chan) char *a; int chan;
  441.  {int n; char c; n=0;
  442.   if( (c = *a++ = getc(chan)) == VOID) return(VOID) ;
  443.   if( c == LF) {*a = NULL; return(ONE) ; }
  444.   while( (*a=getc(chan)) != LF ) ++a,++n ;
  445.   *++a = NULL; return(++n) ;
  446.  }
  447. /* same as getl but with LF replaced by null */
  448. getl0(a,chan) char *a; int chan;
  449.  {int n; n=getl(a,chan) ; if (n == VOID) return(VOID);
  450.   *(a+n) = NULL ; return(n);
  451.  }
  452. /* cmp strs p and q; return -1,0,1, for p<q,p=q,p>q */
  453. strcmp(p,q) char *p,*q;
  454.  {while(*p == *q) {if (*p++ == NULL) return(SAME) ; else ++q; }
  455.   return(*p < *q ? LESS:MORE) ;
  456.  }
  457. /* change runs of c to single c thruout s */
  458. deruns(c,s) char c,*s;
  459.  {pairdec(c,c,s) ;
  460.  }
  461. /* change ab to b thruout s */
  462. pairdec(a,b,s) char a,b,*s;
  463.  {char *t;
  464.   for (t=s; *s = *t; )
  465.     if( (*++t != b) || (*s != a) ) s++ ;
  466.  }
  467. /* print signed dec int -- assumes ASCII */
  468. printd(n) int n;
  469.  {int i;
  470.   if(n < 0) {putchar('-'); n = -n ; }
  471.   if( (i=n/10) != 0) printd(i) ;
  472.   putchar(n % 10 + '0') ;
  473.  }
  474. /*copy 1st n bytes of t to s, insert NULL at end*/
  475. strcpyn(s,t,n) char *s,*t; int n;
  476.  {for ( ; n ; n--) *s++ = *t++ ; *s = NULL ;
  477.  }
  478. /*test if str q is at p. rtrn 1 is so, 0 if not*/
  479. strisat(p,q) char *p,*q ;
  480.  {while( *p && *q && (*q == *p) ) p++,q++ ;
  481.   return(*q ? NULL:ONE) ;
  482.  }
  483. /* get a pos. int from kb */
  484. getint()
  485.  {char c; int n;
  486.   for(n=0; isadig(c=getchar()); ) n=10*n + c - '0' ;
  487.   return(n) ;
  488.  }
  489. /* test if byte is a digit */
  490. isadig(c) char c;
  491.  {return( ((c >= '0') && (c <= '9')) ? ONE:NULL ) ;
  492.  }
  493.  
  494.